/* 
* @Author: anchen
* @Date:   2017-07-04 09:29:09
* @Last Modified by:   anchen
* @Last Modified time: 2017-07-04 10:07:46
*/


function tmsImageryProvider(options) {

            options = Cesium.defaultValue(options, {});

            if (!Cesium.defined(options.url)) {
                throw new Cesium.DeveloperError('options.url is required.');
            }

            var url = options.url;

            

            var metadataError;

            function metadataSuccess(xml) {
                var tileFormatRegex = /tileformat/i;
                var tileSetRegex = /tileset/i;
                var tileSetsRegex = /tilesets/i;
                var bboxRegex = /boundingbox/i;
                var srsRegex = /srs/i;
                var format, bbox, tilesets, srs;
                var tilesetsList = []; //list of TileSets

                // Allowing options properties (already copied to that) to override XML values

                // Iterate XML Document nodes for properties
                var nodeList = xml.childNodes[0].childNodes;
                for (var i = 0; i < nodeList.length; i++) {
                    if (tileFormatRegex.test(nodeList.item(i).nodeName)) {
                        format = nodeList.item(i);
                    } else if (tileSetsRegex.test(nodeList.item(i).nodeName)) {
                        tilesets = nodeList.item(i); // Node list of TileSets
                        var tileSetNodes = nodeList.item(i).childNodes;
                        // Iterate the nodes to find all TileSets
                        for (var j = 0; j < tileSetNodes.length; j++) {
                            if (tileSetRegex.test(tileSetNodes.item(j).nodeName)) {
                                // Add them to tilesets list
                                tilesetsList.push(tileSetNodes.item(j));
                            }
                        }
                    } else if (bboxRegex.test(nodeList.item(i).nodeName)) {
                        bbox = nodeList.item(i);
                    } else if (srsRegex.test(nodeList.item(i).nodeName)) {
                        srs = nodeList.item(i).textContent;
                    }
                }

                var fileExtension = Cesium.defaultValue(options.fileExtension, format.getAttribute('extension'));
                var tileWidth = Cesium.defaultValue(options.tileWidth, parseInt(format.getAttribute('width'), 10));
                var tileHeight = Cesium.defaultValue(options.tileHeight, parseInt(format.getAttribute('height'), 10));
                var minimumLevel = Cesium.defaultValue(options.minimumLevel, parseInt(tilesetsList[0].getAttribute('order'), 10));
                var maximumLevel = Cesium.defaultValue(options.maximumLevel, parseInt(tilesetsList[tilesetsList.length - 1].getAttribute('order'), 10));
                var tilingSchemeName = tilesets.getAttribute('profile');
                var tilingScheme = options.tilingScheme;

                if (!defined(tilingScheme)) {
                    if (tilingSchemeName === 'geodetic' || tilingSchemeName === 'global-geodetic') {
                        tilingScheme = new Cesium.GeographicTilingScheme({ellipsoid: options.ellipsoid});
                    } else if (tilingSchemeName === 'mercator' || tilingSchemeName === 'global-mercator') {
                        tilingScheme = new Cesium.WebMercatorTilingScheme({ellipsoid: options.ellipsoid});
                    } else {
                        var message = Cesium.joinUrls(url, 'tilemapresource.xml') + 'specifies an unsupported profile attribute, ' + tilingSchemeName + '.';
                        metadataError = Cesium.TileProviderError.handleError(metadataError, imageryProvider, imageryProvider.errorEvent, message, undefined, undefined, undefined, requestMetadata);
                        if (!metadataError.retry) {
                            Cesium.deferred.reject(new Cesium.RuntimeError(message));
                        }
                        return;
                    }
                }

                //console.log(tilingScheme,rectangle)
                // rectangle handling
                //var rectangle = Cesium.Rectangle.clone(options.rectangle);
                console.log(rectangle)

                if (!Cesium.defined(rectangle)) {
                    var sw;
                    var ne;
                    var swXY;
                    var neXY;

                    // In older versions of gdal x and y values were flipped, which is why we check for an option to flip
                    // the values here as well. Unfortunately there is no way to autodetect whether flipping is needed.
                    var flipXY = Cesium.defaultValue(options.flipXY, false);
                    if (flipXY) {
                        swXY = new Cesium.Cartesian2(parseFloat(bbox.getAttribute('miny')), parseFloat(bbox.getAttribute('minx')));
                        neXY = new Cesium.Cartesian2(parseFloat(bbox.getAttribute('maxy')), parseFloat(bbox.getAttribute('maxx')));
                    } else {
                        swXY = new Cesium.Cartesian2(parseFloat(bbox.getAttribute('minx')), parseFloat(bbox.getAttribute('miny')));
                        neXY = new Cesium.Cartesian2(parseFloat(bbox.getAttribute('maxx')), parseFloat(bbox.getAttribute('maxy')));
                    }

                    // Determine based on the profile attribute if this tileset was generated by gdal2tiles.py, which
                    // uses 'mercator' and 'geodetic' profiles, or by a tool compliant with the TMS standard, which is
                    // 'global-mercator' and 'global-geodetic' profiles. In the gdal2Tiles case, X and Y are always in
                    // geodetic degrees.
                    var isGdal2tiles = tilingSchemeName === 'geodetic' || tilingSchemeName === 'mercator';
                    if (tilingScheme instanceof GeographicTilingScheme || isGdal2tiles) {
                        sw = Cesium.Cartographic.fromDegrees(swXY.x, swXY.y);
                        ne = Cesium.Cartographic.fromDegrees(neXY.x, neXY.y);
                    } else {
                        var projection = tilingScheme.projection;
                        sw = projection.unproject(swXY);
                        ne = projection.unproject(neXY);
                    }

                    rectangle = new Cesium.Rectangle(sw.longitude, sw.latitude, ne.longitude, ne.latitude);
                }
                // The rectangle must not be outside the bounds allowed by the tiling scheme.
                if (rectangle.west < tilingScheme.rectangle.west) {
                    rectangle.west = tilingScheme.rectangle.west;
                }
                if (rectangle.east > tilingScheme.rectangle.east) {
                    rectangle.east = tilingScheme.rectangle.east;
                }
                if (rectangle.south < tilingScheme.rectangle.south) {
                    rectangle.south = tilingScheme.rectangle.south;
                }
                if (rectangle.north > tilingScheme.rectangle.north) {
                    rectangle.north = tilingScheme.rectangle.north;
                }

                // Check the number of tiles at the minimum level.  If it's more than four,
                // try requesting the lower levels anyway, because starting at the higher minimum
                // level will cause too many tiles to be downloaded and rendered.
                var swTile = tilingScheme.Cesium.positionToTileXY(Rectangle.southwest(rectangle), minimumLevel);
                var neTile = tilingScheme.Cesium.positionToTileXY(Rectangle.northeast(rectangle), minimumLevel);
                var tileCount = (Math.abs(neTile.x - swTile.x) + 1) * (Math.abs(neTile.y - swTile.y) + 1);
                if (tileCount > 4) {
                    minimumLevel = 0;
                }

                var templateUrl = Cesium.joinUrls(url, '{z}/{x}/{reverseY}.' + fileExtension);

                deferred.resolve({
                    url: templateUrl,
                    tilingScheme: tilingScheme,
                    rectangle: rectangle,
                    tileWidth: tileWidth,
                    tileHeight: tileHeight,
                    minimumLevel: minimumLevel,
                    maximumLevel: maximumLevel,
                    proxy: options.proxy,
                    tileDiscardPolicy: options.tileDiscardPolicy,
                    credit: options.credit
                });
            }

            function metadataFailure(error) {
                // Can't load XML, still allow options and defaults
                var fileExtension = Cesium.defaultValue(options.fileExtension, 'png');
                var tileWidth = Cesium.defaultValue(options.tileWidth, 256);
                var tileHeight = Cesium.defaultValue(options.tileHeight, 256);
                var minimumLevel = Cesium.defaultValue(options.minimumLevel, 0);
                var maximumLevel = options.maximumLevel;
                var tilingScheme = Cesium.defined(options.tilingScheme) ? options.tilingScheme : new Cesium.WebMercatorTilingScheme({ellipsoid: options.ellipsoid});
                var rectangle = Cesium.defaultValue(options.rectangle, tilingScheme.rectangle);

                var templateUrl = Cesium.joinUrls(url, '{z}/{x}/{reverseY}.' + fileExtension);

                deferred.resolve({
                    url: templateUrl,
                    tilingScheme: tilingScheme,
                    rectangle: rectangle,
                    tileWidth: tileWidth,
                    tileHeight: tileHeight,
                    minimumLevel: minimumLevel,
                    maximumLevel: maximumLevel,
                    proxy: options.proxy,
                    tileDiscardPolicy: options.tileDiscardPolicy,
                    credit: options.credit
                });
            }

            function requestMetadata() {
                var resourceUrl = Cesium.joinUrls(url, 'tilemapresource.xml');
                var proxy = options.proxy;
                if (Cesium.defined(proxy)) {
                    resourceUrl = proxy.getURL(resourceUrl);
                }
                // Try to load remaining parameters from XML
                Cesium.loadXML(resourceUrl).then(metadataSuccess).otherwise(metadataFailure);
            }
            var deferred = when.defer();
            var imageryProvider = new Cesium.UrlTemplateImageryProvider(deferred.promise);
            requestMetadata();
            return imageryProvider;
}